﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "QtCommandButtonMenu.h"
#include "ICommandButtonMenuDefinition.h"
#include "IMenuItemDefinition.h"
#include "ICommandMenuItemDefinition.h"
#include "ProcessCommandUtil.h"
#include "GbmpNew.h"
#include "IControlDefinitionChangeEventArgs.h"
#include "ControlDefinitionChangeEvent.h"
#include "IMenuItemContainerDefinition.h"
#include "CommandParameters.h"
#include "UiQtUtil.h"  
#include "ControlDefinitionUtil.h"
#include "ICommandManager.h"
#include "ICommand.h"

#include <QMenu>

#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"

namespace gcmp
{

QtCommandButtonMenu::QtCommandButtonMenu(OwnerPtr<ICommandButtonMenuDefinition> pControlDefinition)
    : QToolButton()
    , m_pControlDefinition(TransferOwnership(pControlDefinition))
{
    if (!m_pControlDefinition)
    {
        DBG_WARN(L"pControlDefinition为空",L"GDMPLab",L"2024-03-30");
        return;
    }

    //// member
    ////m_pControlDefinition.Reset(pControlDefinition);
    //m_pMenuStyle = NEW_AS_OWNER_PTR(GbmpRibbonStyle);

    // button
    QAction* pButtonAction = NEW_AS_QT_CHILD(QAction, this);
    pButtonAction->setProperty(IS_DEFINITION, true);
    pButtonAction->setText(QString::fromStdWString(m_pControlDefinition->GetCaption()));
    pButtonAction->setCheckable(true);
    pButtonAction->setToolTip(QString::fromStdWString(m_pControlDefinition->GetTooltip()));
    pButtonAction->setIcon(QIcon(QString::fromStdWString(m_pControlDefinition->GetIconPath())));
    setDefaultAction(pButtonAction);
    connect(pButtonAction, &QAction::triggered, this, &QtCommandButtonMenu::OnMenuTriggered);

    setToolButtonStyle(Qt::ToolButtonIconOnly);
    setObjectName(QString::fromStdWString(m_pControlDefinition->GetId()));
    setProperty(IS_DEFINITION, true);

    // menu
    QMenu* pMenu = NEW_AS_QT_CHILD(QMenu, this);
    //pMenu->setStyle(m_pMenuStyle.get());
    pMenu->setProperty(IS_DEFINITION, true);

    //通过样式表修改菜单默认的Item高度和选中效果
    pMenu->setStyleSheet("QMenu { background-color: white; border: 1px solid gray;icon-size: 32px;}\
                         QMenu::item {background-color: transparent;padding:2px 32px;margin:0px 1px;}\
                         QMenu::item:selected {background-color: #CCDAE7; border-width:1px;border-style:solid; border-color:#19649F;}");

    setMenu(pMenu);
    setPopupMode(QToolButton::MenuButtonPopup);

    // menu items
    std::vector<IMenuItemDefinition*> menuItems = m_pControlDefinition->GetAllItems();
    for (auto pItem : menuItems)
    {
        AddMenuItem(menu(), pItem);
    }
    IControlDefinitionChangeEvent* pControlDefinitionChangeEvent = ControlDefinitionUtil::GetControlDefinitionChangeEvent(m_pControlDefinition.get());
    if (pControlDefinitionChangeEvent)
    {
        pControlDefinitionChangeEvent->Add(this);
    }
}

QtCommandButtonMenu::~QtCommandButtonMenu()
{
    IControlDefinitionChangeEvent* pControlDefinitionChangeEvent = ControlDefinitionUtil::GetControlDefinitionChangeEvent(m_pControlDefinition.get());
    if (pControlDefinitionChangeEvent)
    {
        pControlDefinitionChangeEvent->Delete(this);
    }
}

IControlDefinition* QtCommandButtonMenu::GetControlDefinition() const
{
    return const_cast<ICommandButtonMenuDefinition*>(m_pControlDefinition.get());
}

void QtCommandButtonMenu::On(IControlDefinitionChangeEventArgs* pArgs)
{
    DBG_WARN_AND_RETURN_VOID_UNLESS(pArgs, L"pArgs为空",L"GDMPLab",L"2024-03-30");
    if (pArgs->GetType() == ControlDefinitionChangeEventType::Add)
    {
        const IMenuItemDefinition* pMenuItemDefine = dynamic_cast<const IMenuItemDefinition*>(pArgs->GetControlDefinition());
        DBG_WARN_AND_RETURN_VOID_UNLESS(pMenuItemDefine, L"pMenuItemDefine为空",L"GDMPLab",L"2024-03-30");
        AddMenuItem(menu(), pMenuItemDefine);
    }
    else if (pArgs->GetType() == ControlDefinitionChangeEventType::DeleteAll)
    {
        DBG_WARN_AND_RETURN_VOID_UNLESS(menu(), L"menu()为空",L"GDMPLab",L"2024-03-30");
        menu()->clear();
    }
    else if (pArgs->GetType() == ControlDefinitionChangeEventType::Insert)
    {
        DBG_WARN_AND_RETURN_VOID_UNLESS(menu(), L"menu()为空",L"GDMPLab",L"2024-03-30");
        int insertControlDefinitionIndex = pArgs->GetDeleteOrInsertControlDefinitionIndex();
       
        QList<QAction *> actionList = menu()->actions();
        DBG_WARN_AND_RETURN_VOID_UNLESS(insertControlDefinitionIndex < actionList.size() && insertControlDefinitionIndex >= 0, L"index不正确",L"GDMPLab",L"2024-03-30");
        if (const ICommandMenuItemDefinition* pControlDefinition = dynamic_cast<const ICommandMenuItemDefinition*>(pArgs->GetControlDefinition()))
        {
            QAction* pAction = NEW_AS_QT_CHILD(QAction, this);
            pAction->setText(QString::fromStdWString(pControlDefinition->GetCaption()));
            pAction->setCheckable(true);
            pAction->setChecked(pControlDefinition->IsChecked());
            pAction->setToolTip(QString::fromStdWString(pControlDefinition->GetTooltip()));
            pAction->setIcon(QIcon(QString::fromStdWString(pControlDefinition->GetIconPath())));
            pAction->setProperty("CommandId", QString::fromStdWString(pControlDefinition->GetCommandId()));
            connect(pAction, &QAction::triggered, this, &QtCommandButtonMenu::OnMenuItemTriggered);
            menu()->insertAction(actionList[insertControlDefinitionIndex], pAction);
        }
        else if (const IMenuItemContainerDefinition* pMenuItemDefinition = dynamic_cast<const IMenuItemContainerDefinition*>(pArgs->GetControlDefinition()))
        {
            std::vector<const IMenuItemDefinition* > subMenuItems = pMenuItemDefinition->GetSubMenuItems();
            if (subMenuItems.empty())
                return;
            QMenu *pSubMenu = NEW_AS_QT_CHILD(QMenu, QString::fromStdWString(pMenuItemDefinition->GetCaption()), this);
            for (auto iter : subMenuItems)
            {
                AddMenuItem(pSubMenu, iter);
            }
            menu()->insertMenu(actionList[insertControlDefinitionIndex], pSubMenu);
        }
        
    }

    else if (pArgs->GetType() == ControlDefinitionChangeEventType::Other)
    {
        const IControlDefinition* pCtrlDef = pArgs->GetControlDefinition();
        if (const ICommandMenuItemDefinition* pControlDefinition = dynamic_cast<const ICommandMenuItemDefinition*>(pCtrlDef))
        {
            QMenu* pMenu = menu();
            if (pMenu == nullptr) return;
            QList<QAction*> lstAction = pMenu->actions();
            for (QAction* pAction : lstAction)
            {
                if(pAction == nullptr) continue;
                std::wstring cmdId = pAction->property("CommandId").toString().toStdWString();
                if (cmdId != pControlDefinition->GetCommandId()) continue;
                pAction->setChecked(pControlDefinition->IsChecked());
                pAction->setText(QString::fromStdWString(pControlDefinition->GetCaption()));
                pAction->setToolTip(QString::fromStdWString(pControlDefinition->GetTooltip()));
                pAction->setIcon(QIcon(QString::fromStdWString(pControlDefinition->GetIconPath())));
                break;
            }
        }
        else if (const ICommandButtonMenuDefinition* pControlDefinition = dynamic_cast<const ICommandButtonMenuDefinition*>(pCtrlDef))
        {
            if (QAction* pAction = defaultAction())
            {
                pAction->setText(QString::fromStdWString(pControlDefinition->GetCaption()));
                pAction->setToolTip(QString::fromStdWString(pControlDefinition->GetTooltip()));
                pAction->setIcon(QIcon(QString::fromStdWString(pControlDefinition->GetIconPath())));
            }
        }
    }
}

void QtCommandButtonMenu::UpdateStatus()
{
    DBG_WARN_AND_RETURN_VOID_UNLESS(m_pControlDefinition, L"pControlDefinition为空",L"GDMPLab",L"2024-03-30");

    bool visible = m_pControlDefinition->IsVisible();
    setVisible(visible);
    if (!visible)
        return;
    setEnabled(m_pControlDefinition->IsEnabled());
    QMenu * pMenu = menu();
    QList<QAction*> menuActions = pMenu->actions();
    for (int n = 0; n < menuActions.length(); ++n)
    {
        std::wstring commandId = menuActions.at(n)->property("CommandId").toString().toStdWString();
        ICommand* pCommand = ICommandManager::Get()->GetCommand(commandId);

        // 如果没绑定Command则不设置
        if (!pCommand)
            continue;

        menuActions.at(n)->setVisible(pCommand->IsVisible());
        menuActions.at(n)->setEnabled(pCommand->IsEnabled());
    }
}

void QtCommandButtonMenu::OnMenuItemTriggered(bool checked)
{
    Q_UNUSED(checked);

    // 回放过程中不必理会用户输入
    //if (gcmp::IJournalManager::Get()->IsInReplay())
    //    return;

    QAction* pAction = qobject_cast<QAction*>(sender());
    DBG_WARN_AND_RETURN_VOID_UNLESS(pAction, L"pAction为空",L"GDMPLab",L"2024-03-30");

    QMenu * pMenu = menu();
    QList<QAction*> pMenuActions = pMenu->actions();
    //将菜单项默认值全部更改为未选中状态。
    for (auto& pMenuAction : pMenuActions)
    {
        if (!pMenuAction)
            continue;
        pMenuAction->setChecked(false);
    }

    for (auto& pMenuAction : pMenuActions)
    {
        if (!pMenuAction)
            continue;

        if (pAction->parentWidget() == pMenuAction->parentWidget() && pAction->text() == pMenuAction->text() && pAction->iconText() == pMenuAction->iconText())
        {
            pMenuAction->setChecked(true);
            break;
        }
    }

    std::wstring commandId = pAction->property("CommandId").toString().toStdWString();
    gcmp::CommandParameters dummyMap;
    ProcessCommandUtil::ProcessStatusBarCommand(commandId, dummyMap, pAction);
}

void QtCommandButtonMenu::OnMenuTriggered(bool checked)
{
    DBG_WARN_AND_RETURN_VOID_UNLESS(m_pControlDefinition, L"pControlDefinition为空",L"GDMPLab",L"2024-03-30");
    std::wstring commandId = m_pControlDefinition->GetCommandId();
    if (!commandId.empty())
    {
        ProcessCommandUtil::ProcessRibbonBarCommand(commandId, {}, sender());
    }
}

void QtCommandButtonMenu::AddMenuItem(QMenu *pMenu, const IMenuItemDefinition* pMenuItemDefinition)
{
    DBG_WARN_AND_RETURN_VOID_UNLESS(pMenuItemDefinition, L"pMenuItemDefinition为空",L"GDMPLab",L"2024-03-30");
    DBG_WARN_AND_RETURN_VOID_UNLESS(pMenu, L"pMenu为空",L"GDMPLab",L"2024-03-30");

    std::wstring text = pMenuItemDefinition->GetCaption();
    std::wstring iconPath = pMenuItemDefinition->GetIconPath();

    if (const ICommandMenuItemDefinition* define = dynamic_cast<const ICommandMenuItemDefinition*>(pMenuItemDefinition))
    {
        QAction* pAction = pMenu->addAction(QIcon(QString::fromStdWString(iconPath)), QString::fromStdWString(text));
        pAction->setProperty(IS_DEFINITION, true);
        pAction->setCheckable(true);
        pAction->setToolTip(QString::fromStdWString(pMenuItemDefinition->GetTooltip()));
        pAction->setChecked(define->IsChecked());
        pAction->setProperty("CommandId", QString::fromStdWString(pMenuItemDefinition->GetCommandId()));
        connect(pAction, &QAction::triggered, this, &QtCommandButtonMenu::OnMenuItemTriggered);
        return;
    }
    std::vector<const IMenuItemDefinition* > subMenuItems = pMenuItemDefinition->GetSubMenuItems();
    if (subMenuItems.empty())
        return;

    QMenu *pSubMenu = pMenu->addMenu(QIcon(QString::fromStdWString(iconPath)), QString::fromStdWString(text));
    pSubMenu->setProperty(IS_DEFINITION, true);
    for (auto iter : subMenuItems)
    {
        AddMenuItem(pSubMenu, iter);
    }
}

}